using System;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Web;

using Microsoft.Win32;

using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;

using WoWAddonRefresh.Entities;
using Schematrix;

using System.Data.Linq;
using System.Linq;
using System.Linq.Expressions;

using System.Net;

namespace WoWAddonRefresh {
    public class FormMain : System.Windows.Forms.Form {

        #region Forms.Controls

        private System.Windows.Forms.TextBox tb_username;
        private System.Windows.Forms.TextBox tb_password;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.Button btn_go;
        private System.Windows.Forms.Button btn_update;
        private System.Windows.Forms.Button btn_exit;
        private System.Windows.Forms.Label lbl_current_action;
        private System.Windows.Forms.MenuItem menuItem1;
        private System.Windows.Forms.MenuItem menuItem2;
        private System.Windows.Forms.MenuItem menuItem3;
        private System.Windows.Forms.ContextMenu contextMenu;
        private System.Windows.Forms.MenuItem menuItem4;
        private System.Windows.Forms.MenuItem menuItem5;
        private System.Windows.Forms.Timer timer;
        private System.ComponentModel.IContainer components;
        private DataGridView dgvAddons;
        private ProgressBar progressBar;
        private MenuItem menuItem6;
        private MenuItem menuItem7;
        private MenuItem menuItem9;
        private MenuItem menuItem8;
        private DataGridViewCheckBoxColumn addonCheckedDataGridViewCheckBoxColumn;
        private DataGridViewCheckBoxColumn Checked;
        private DataGridViewTextBoxColumn nameDataGridViewTextBoxColumn;
        private DataGridViewTextBoxColumn localDateDataGridViewTextBoxColumn;
        private DataGridViewTextBoxColumn uploadDateDataGridViewTextBoxColumn;
        private DataGridViewCheckBoxColumn skipDataGridViewCheckBoxColumn;
        private Button btnOptions;

        #endregion Forms.Controls

        protected override void Dispose(bool disposing) {
            if (disposing) {
                if (components != null) {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent() {
            this.components = new System.ComponentModel.Container();
            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
            System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain));
            this.tb_username = new System.Windows.Forms.TextBox();
            this.tb_password = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.btn_go = new System.Windows.Forms.Button();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.dgvAddons = new System.Windows.Forms.DataGridView();
            this.btn_exit = new System.Windows.Forms.Button();
            this.btn_update = new System.Windows.Forms.Button();
            this.lbl_current_action = new System.Windows.Forms.Label();
            this.contextMenu = new System.Windows.Forms.ContextMenu();
            this.menuItem1 = new System.Windows.Forms.MenuItem();
            this.menuItem2 = new System.Windows.Forms.MenuItem();
            this.menuItem3 = new System.Windows.Forms.MenuItem();
            this.menuItem4 = new System.Windows.Forms.MenuItem();
            this.menuItem6 = new System.Windows.Forms.MenuItem();
            this.menuItem7 = new System.Windows.Forms.MenuItem();
            this.menuItem9 = new System.Windows.Forms.MenuItem();
            this.menuItem8 = new System.Windows.Forms.MenuItem();
            this.menuItem5 = new System.Windows.Forms.MenuItem();
            this.timer = new System.Windows.Forms.Timer(this.components);
            this.progressBar = new System.Windows.Forms.ProgressBar();
            this.btnOptions = new System.Windows.Forms.Button();
            this.AddonCollection2BindingSource = new System.Windows.Forms.BindingSource(this.components);
            this.Checked = new System.Windows.Forms.DataGridViewCheckBoxColumn();
            this.nameDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.localDateDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.uploadDateDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
            this.skipDataGridViewCheckBoxColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn();
            this.groupBox1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvAddons)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.AddonCollection2BindingSource)).BeginInit();
            this.SuspendLayout();
            // 
            // tb_username
            // 
            this.tb_username.Location = new System.Drawing.Point(8, 6);
            this.tb_username.Name = "tb_username";
            this.tb_username.Size = new System.Drawing.Size(211, 20);
            this.tb_username.TabIndex = 0;
            this.tb_username.Text = "Username";
            // 
            // tb_password
            // 
            this.tb_password.Location = new System.Drawing.Point(8, 36);
            this.tb_password.Name = "tb_password";
            this.tb_password.PasswordChar = '+';
            this.tb_password.Size = new System.Drawing.Size(211, 20);
            this.tb_password.TabIndex = 1;
            this.tb_password.Text = "password";
            this.tb_password.KeyUp += new System.Windows.Forms.KeyEventHandler(this.tb_password_KeyUp);
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(225, 9);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(56, 23);
            this.label1.TabIndex = 2;
            this.label1.Text = "login";
            // 
            // label2
            // 
            this.label2.Location = new System.Drawing.Point(225, 39);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(56, 23);
            this.label2.TabIndex = 3;
            this.label2.Text = "password";
            // 
            // btn_go
            // 
            this.btn_go.Location = new System.Drawing.Point(8, 62);
            this.btn_go.Name = "btn_go";
            this.btn_go.Size = new System.Drawing.Size(211, 23);
            this.btn_go.TabIndex = 4;
            this.btn_go.Text = "login && get addon names";
            this.btn_go.Click += new System.EventHandler(this.btn_go_Click);
            // 
            // groupBox1
            // 
            this.groupBox1.Controls.Add(this.dgvAddons);
            this.groupBox1.Controls.Add(this.btn_exit);
            this.groupBox1.Controls.Add(this.btn_update);
            this.groupBox1.Location = new System.Drawing.Point(8, 128);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(395, 320);
            this.groupBox1.TabIndex = 5;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Addons";
            // 
            // dgvAddons
            // 
            this.dgvAddons.AccessibleRole = System.Windows.Forms.AccessibleRole.None;
            this.dgvAddons.AllowUserToAddRows = false;
            this.dgvAddons.AllowUserToDeleteRows = false;
            this.dgvAddons.AllowUserToResizeRows = false;
            this.dgvAddons.AutoGenerateColumns = false;
            this.dgvAddons.BackgroundColor = System.Drawing.SystemColors.Window;
            this.dgvAddons.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
            this.dgvAddons.CausesValidation = false;
            dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
            dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
            dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
            dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
            dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.WindowText;
            dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
            dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
            this.dgvAddons.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
            this.dgvAddons.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dgvAddons.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
            this.Checked,
            this.nameDataGridViewTextBoxColumn,
            this.localDateDataGridViewTextBoxColumn,
            this.uploadDateDataGridViewTextBoxColumn,
            this.skipDataGridViewCheckBoxColumn});
            this.dgvAddons.DataSource = this.AddonCollection2BindingSource;
            this.dgvAddons.GridColor = System.Drawing.SystemColors.Window;
            this.dgvAddons.Location = new System.Drawing.Point(12, 19);
            this.dgvAddons.MultiSelect = false;
            this.dgvAddons.Name = "dgvAddons";
            this.dgvAddons.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
            dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
            dataGridViewCellStyle2.BackColor = System.Drawing.SystemColors.Control;
            dataGridViewCellStyle2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
            dataGridViewCellStyle2.ForeColor = System.Drawing.SystemColors.WindowText;
            dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.InactiveBorder;
            dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
            dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
            this.dgvAddons.RowHeadersDefaultCellStyle = dataGridViewCellStyle2;
            this.dgvAddons.RowHeadersVisible = false;
            dataGridViewCellStyle3.SelectionBackColor = System.Drawing.Color.White;
            this.dgvAddons.RowsDefaultCellStyle = dataGridViewCellStyle3;
            this.dgvAddons.RowTemplate.DefaultCellStyle.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
            this.dgvAddons.RowTemplate.Height = 18;
            this.dgvAddons.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
            this.dgvAddons.Size = new System.Drawing.Size(377, 261);
            this.dgvAddons.TabIndex = 5;
            this.dgvAddons.Leave += new System.EventHandler(this.dgvAddons_Leave);
            this.dgvAddons.MouseUp += new System.Windows.Forms.MouseEventHandler(this.dgvAddons_MouseUp);
            this.dgvAddons.KeyUp += new System.Windows.Forms.KeyEventHandler(this.dgvAddons_KeyUp);
            // 
            // btn_exit
            // 
            this.btn_exit.Location = new System.Drawing.Point(199, 286);
            this.btn_exit.Name = "btn_exit";
            this.btn_exit.Size = new System.Drawing.Size(186, 23);
            this.btn_exit.TabIndex = 3;
            this.btn_exit.Text = "exit";
            this.btn_exit.Click += new System.EventHandler(this.btn_exit_Click);
            // 
            // btn_update
            // 
            this.btn_update.Enabled = false;
            this.btn_update.Location = new System.Drawing.Point(10, 286);
            this.btn_update.Name = "btn_update";
            this.btn_update.Size = new System.Drawing.Size(186, 23);
            this.btn_update.TabIndex = 1;
            this.btn_update.Text = "update";
            this.btn_update.Click += new System.EventHandler(this.btn_update_Click);
            // 
            // lbl_current_action
            // 
            this.lbl_current_action.Location = new System.Drawing.Point(8, 112);
            this.lbl_current_action.Name = "lbl_current_action";
            this.lbl_current_action.Size = new System.Drawing.Size(395, 16);
            this.lbl_current_action.TabIndex = 11;
            // 
            // contextMenu
            // 
            this.contextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
            this.menuItem1,
            this.menuItem2,
            this.menuItem3,
            this.menuItem4,
            this.menuItem6,
            this.menuItem7,
            this.menuItem9,
            this.menuItem8});
            this.contextMenu.Popup += new System.EventHandler(this.contextMenu_Popup);
            // 
            // menuItem1
            // 
            this.menuItem1.Index = 0;
            this.menuItem1.Text = "Select all";
            this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click);
            // 
            // menuItem2
            // 
            this.menuItem2.Index = 1;
            this.menuItem2.Text = "Select none";
            this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click);
            // 
            // menuItem3
            // 
            this.menuItem3.Index = 2;
            this.menuItem3.Text = "Select reverse";
            this.menuItem3.Click += new System.EventHandler(this.menuItem3_Click);
            // 
            // menuItem4
            // 
            this.menuItem4.Index = 3;
            this.menuItem4.Text = "Select new";
            this.menuItem4.Click += new System.EventHandler(this.menuItem4_Click);
            // 
            // menuItem6
            // 
            this.menuItem6.Index = 4;
            this.menuItem6.Text = "-";
            // 
            // menuItem7
            // 
            this.menuItem7.Index = 5;
            this.menuItem7.Text = "Description";
            this.menuItem7.Click += new System.EventHandler(this.menuItem7_Click);
            // 
            // menuItem9
            // 
            this.menuItem9.Index = 6;
            this.menuItem9.Text = "Open addon webpage";
            this.menuItem9.Click += new System.EventHandler(this.menuItem9_Click);
            // 
            // menuItem8
            // 
            this.menuItem8.Index = 7;
            this.menuItem8.Text = "Download addon";
            this.menuItem8.Click += new System.EventHandler(this.menuItem8_Click);
            // 
            // menuItem5
            // 
            this.menuItem5.Index = -1;
            this.menuItem5.Text = "";
            // 
            // timer
            // 
            this.timer.Interval = 1000;
            this.timer.Tick += new System.EventHandler(this.timer_Tick);
            // 
            // progressBar
            // 
            this.progressBar.Location = new System.Drawing.Point(8, 91);
            this.progressBar.Name = "progressBar";
            this.progressBar.Size = new System.Drawing.Size(392, 10);
            this.progressBar.TabIndex = 16;
            // 
            // btnOptions
            // 
            this.btnOptions.Location = new System.Drawing.Point(270, 3);
            this.btnOptions.Name = "btnOptions";
            this.btnOptions.Size = new System.Drawing.Size(130, 23);
            this.btnOptions.TabIndex = 20;
            this.btnOptions.Text = "Options";
            this.btnOptions.UseVisualStyleBackColor = true;
            this.btnOptions.Click += new System.EventHandler(this.btnOptions_Click);
            // 
            // AddonCollection2BindingSource
            // 
            this.AddonCollection2BindingSource.DataSource = typeof(System.Collections.Generic.List<Addon>);
            // 
            // Checked
            // 
            this.Checked.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
            this.Checked.DataPropertyName = "Checked";
            this.Checked.HeaderText = "";
            this.Checked.MinimumWidth = 20;
            this.Checked.Name = "Checked";
            this.Checked.Resizable = System.Windows.Forms.DataGridViewTriState.False;
            this.Checked.Width = 20;
            // 
            // nameDataGridViewTextBoxColumn
            // 
            this.nameDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
            this.nameDataGridViewTextBoxColumn.DataPropertyName = "Name";
            this.nameDataGridViewTextBoxColumn.HeaderText = "Name";
            this.nameDataGridViewTextBoxColumn.Name = "nameDataGridViewTextBoxColumn";
            this.nameDataGridViewTextBoxColumn.ReadOnly = true;
            // 
            // localDateDataGridViewTextBoxColumn
            // 
            this.localDateDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
            this.localDateDataGridViewTextBoxColumn.DataPropertyName = "LocalDate";
            this.localDateDataGridViewTextBoxColumn.HeaderText = "LocalDate";
            this.localDateDataGridViewTextBoxColumn.Name = "localDateDataGridViewTextBoxColumn";
            this.localDateDataGridViewTextBoxColumn.ReadOnly = true;
            this.localDateDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
            this.localDateDataGridViewTextBoxColumn.Width = 81;
            // 
            // uploadDateDataGridViewTextBoxColumn
            // 
            this.uploadDateDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
            this.uploadDateDataGridViewTextBoxColumn.DataPropertyName = "UploadDate";
            this.uploadDateDataGridViewTextBoxColumn.HeaderText = "UploadDate";
            this.uploadDateDataGridViewTextBoxColumn.Name = "uploadDateDataGridViewTextBoxColumn";
            this.uploadDateDataGridViewTextBoxColumn.ReadOnly = true;
            this.uploadDateDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
            this.uploadDateDataGridViewTextBoxColumn.Width = 89;
            // 
            // skipDataGridViewCheckBoxColumn
            // 
            this.skipDataGridViewCheckBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
            this.skipDataGridViewCheckBoxColumn.DataPropertyName = "Skip";
            this.skipDataGridViewCheckBoxColumn.HeaderText = "Skip";
            this.skipDataGridViewCheckBoxColumn.MinimumWidth = 34;
            this.skipDataGridViewCheckBoxColumn.Name = "skipDataGridViewCheckBoxColumn";
            this.skipDataGridViewCheckBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.False;
            this.skipDataGridViewCheckBoxColumn.Width = 34;
            // 
            // FormMain
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(413, 454);
            this.Controls.Add(this.btnOptions);
            this.Controls.Add(this.progressBar);
            this.Controls.Add(this.lbl_current_action);
            this.Controls.Add(this.groupBox1);
            this.Controls.Add(this.btn_go);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.tb_password);
            this.Controls.Add(this.tb_username);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.Name = "FormMain";
            this.Text = "WoWInterface.com Favorites Refresher";
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
            this.groupBox1.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.dgvAddons)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.AddonCollection2BindingSource)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        #endregion

        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.Run(new FormMain());
        }



        public FormMain() {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            Credo = IStorage.GetCredentials();

            tb_username.Text = Credo == null || Credo.Username == null ? "Username" : Credo.Username;
            tb_password.Text = Credo == null || Credo.Password == null ? "Password" : Credo.Password;

            AddonCollection2BindingSource.DataSource = Addons;
            MainRequest = new Request();
            MainRequest.MainForm = this;

            if (Credo == null) {
                Credo = new Credentials();
                SetStatus("Fill username and password and press login...");
            }



            //cb_save.Checked = Credo.SaveCredentials;
            //cb_backup.Checked = Credo.MakeBackup;
            //cb_nopatch.Checked = Credo.AddNopatchFile;


            // SavedAddons = StaticContext.DBContext.Addon.Where(a => a.FileName != null).ToList();
            //(AddonCollection)IStorage.GetSavedAddonList(WoWFolder);
        }

        public void dgvAddons_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) {
            if (e.ListChangedType == ListChangedType.Reset) {
                ColorAddons();
            }
        }

        #region Variables

        private DateTime RestrictionDate = DateTime.MinValue;
        private List<Addon> Addons = new List<Addon>();
        private List<Addon> SavedAddons {
            get {
                return StaticContext.DBContext.Addon.Where(a => a.Name != null).ToList();
            }
        }
        private WorkingThreadCollection WorkingThreads = new WorkingThreadCollection();
        private Request MainRequest = null;
        private BindingSource AddonCollection2BindingSource;
        private Credentials Credo = new Credentials();
        private bool ExitFlag = false;

        #endregion Variables

        #region Properties

        public bool SaveCredentials = true;

        public bool MakeBackup = false;

        public bool TryContinuously = false;



        string farFolder;
        private string FARFolder {
            get {
                if (farFolder == null) {
                    RegistryKey pRegKey = Registry.CurrentUser;
                    pRegKey = pRegKey.OpenSubKey("SOFTWARE\\HexNeo");
                    farFolder = (pRegKey == null) ? null : (pRegKey.GetValue("FARInstallPath") == null ? null : pRegKey.GetValue("FARInstallPath").ToString());
                }
                return farFolder;
            }
        }

        protected int MaxTryCount {
            get {
                return Credo.TryContiniously ? 999 : 4;
            }
        }
        #endregion Properties

        #region Threading

        delegate void SetProgressCallback(int progress);
        public void SetProgress(int progress) {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.progressBar.InvokeRequired) {
                SetProgressCallback setProgressCallback = new SetProgressCallback(SetProgress);
                this.Invoke(setProgressCallback, new object[] { progress });
            }
            else {
                this.progressBar.Value = progress;
                this.Refresh();
            }
        }

        delegate void SetStatusCallback(string text);
        public void SetStatus(string text) {
            if (this.lbl_current_action.InvokeRequired) {
                SetStatusCallback setStatusCallback = new SetStatusCallback(SetStatus);
                this.Invoke(setStatusCallback, new object[] { text });
            }
            else {
                this.lbl_current_action.Text = text;
                this.lbl_current_action.Refresh();
                // this.Refresh();
            }
        }

        delegate void UpdateButtonEnabledCallback(bool enabled);
        public void UpdateButtonEnabled(bool enabled) {
            if (this.btn_update.InvokeRequired) {
                UpdateButtonEnabledCallback updateButtonEnabledCallback = new UpdateButtonEnabledCallback(UpdateButtonEnabled);
                this.Invoke(updateButtonEnabledCallback, new object[] { enabled });
            }
            else {
                this.btn_update.Enabled = enabled;
                this.Refresh();
            }
        }

        delegate void EndEditAddonsCallback();
        private void EndEditAddons() {
            if (this.dgvAddons.InvokeRequired) {
                EndEditAddonsCallback endEditAddonsCallback = new EndEditAddonsCallback(EndEditAddons);
                this.Invoke(endEditAddonsCallback, new object[] { });
            }
            else {
                foreach (DataGridViewRow row in dgvAddons.SelectedRows) {
                    row.Selected = false;
                }
                AddonCollection2BindingSource.EndEdit();
                dgvAddons.EndEdit();
                dgvAddons.Update();
                this.Refresh();
            }
        }

        #endregion Threading

        #region Button Events


        private void Login(Credentials credentials) {
            SetProgress(10);
            SetStatus("Logging in...");
            string url = MainRequest.LoginVBulletin(credentials, Constants.URL_WoWInterface_Login);
            if (url != null) {
                SetProgress(50);
                SetStatus("Logged in, Getting addon names...");

                Addons = MainRequest.GetWoWInterfaceAddons(url, credentials);
                SyncronizeAddons();

                BindListView();
                EndEditAddons();

                SetProgress(70);
                SetStatus("Compare...");

                ColorAddons();

                SetProgress(95);
                this.Refresh();



                SetProgress(100);
                SetStatus("Done...");
                this.Refresh();

                EndEditAddons();

                SetLogin(true);
            }
            else {
                SetLogin(false);
                SetProgress(0);
                SetStatus("Login failed...");
            }
        }

        private void btn_go_Click(object sender, System.EventArgs e) {
            Credo.Username = tb_username.Text.Trim();
            Credo.Password = tb_password.Text.Trim();
            Login(Credo);
        }

        private void UpdateThread() {
            UpdateButtonEnabled(false);
            ThreadStart job = new ThreadStart(AddonsUpdate);
            Thread thread = new Thread(job);
            thread.Start();
            WorkingThread workingThread = new WorkingThread();
            workingThread.ThreadItem = thread;
            WorkingThreads.Add(workingThread);
        }

        private void btn_update_Click(object sender, System.EventArgs e) {
            UpdateThread();
        }

        private void btn_exit_Click(object sender, System.EventArgs e) {
            BeforeClosing(true);
            foreach (WorkingThread workingThread in WorkingThreads) {
                Thread thread = workingThread.ThreadItem;
                if (thread.IsAlive) {
                    thread.Abort();
                }
            }
            this.Dispose();
            this.Close();
        }

        private void btn_compare_Click(object sender, System.EventArgs e) {
            ColorAddons();
        }

        #endregion Button Events

        #region Login
        private string TryLoginCurse(ref Credentials credentials) {
            string result = null;
            FileInfo fileinfo = new FileInfo("WoWAddonRefresh_loginError.html");
            if (fileinfo.Exists) {
                try {
                    fileinfo.Delete();
                }
                catch { /* :( it is not me :) */ }
            }

            string username = tb_username.Text.Trim();
            string password = tb_password.Text.Trim();
            credentials.Username = username;
            credentials.Password = password;

            for (int i = 1; i < MaxTryCount; i++) {
                try {
                    result = MainRequest.SetCookies(ref credentials);
                }
                catch (System.Net.WebException wex) {
                    if (wex.Message.ToLower().IndexOf("timeout") == -1) {
                        // TODO : ???
                    }
                }
                if (!MainRequest.LOGEDIN) SetStatus("Response timeout, will try again. Try nr. " + i + ".");
                else break;
            }

            if (!MainRequest.LOGEDIN) {
                string patchDay = Credo.TryContiniously ? "" : "(try check patch day checkbox, then it will try continously.)";
                MessageBox.Show("Can not login, possible reasons:\n 1) Login or Password invalid\n 2) Your account is locked for some reason\n 3) curse-gaming.com is down\n 4) Patch day " + patchDay + "\n\n\nTry again later.");
                SetProgress(0);
                SetStatus("Login failed...");
                MainRequest.Logout();
                fileinfo = new FileInfo("WoWAddonRefresh_loginError.html");
                if (fileinfo.Exists) {
                    Process process = System.Diagnostics.Process.Start(fileinfo.FullName);
                }
                return null;
            }

            return result;
        }

        private string TryLoginWoWInterface(ref Credentials credentials) {
            string result = null;
            FileInfo fileinfo = new FileInfo("WoWAddonRefresh_loginError.html");
            if (fileinfo.Exists) {
                try {
                    fileinfo.Delete();
                }
                catch { /* :( it is not me :) */ }
            }

            string username = tb_username.Text.Trim();
            string password = tb_password.Text.Trim();
            credentials.Username = username;
            credentials.Password = password;

            for (int i = 1; i < MaxTryCount; i++) {
                try {
                    result = MainRequest.SetCookies(ref credentials);
                }
                catch (System.Net.WebException wex) {
                    if (wex.Message.ToLower().IndexOf("timeout") == -1) {
                        // TODO : ???
                    }
                }
                if (!MainRequest.LOGEDIN) SetStatus("Response timeout, will try again. Try nr. " + i + ".");
                else break;
            }

            if (!MainRequest.LOGEDIN) {
                string patchDay = Credo.TryContiniously ? "" : "(try check patch day checkbox, then it will try continously.)";
                MessageBox.Show("Can not login, possible reasons:\n 1) Login or Password invalid\n 2) Your account is locked for some reason\n 3) curse-gaming.com is down\n 4) Patch day " + patchDay + "\n\n\nTry again later.");
                SetProgress(0);
                SetStatus("Login failed...");
                MainRequest.Logout();
                fileinfo = new FileInfo("WoWAddonRefresh_loginError.html");
                if (fileinfo.Exists) {
                    Process process = System.Diagnostics.Process.Start(fileinfo.FullName);
                }
                return null;
            }

            return result;
        }

        private void SetLogin(bool logged_in) {
            if (logged_in) {
                btn_go.Text = "logout";
            }
            else {
                btn_go.Text = "login && get addon names";
                dgvAddons.Rows.Clear();
            }
            btn_update.Enabled = logged_in;
            tb_password.Enabled = tb_username.Enabled = !logged_in;
        }
        #endregion Login

        private void BindListView() {
            for (int i = 0; i < Addons.Count; i++) {
                Addon addon = Addons[i];
                Addon savedAddon = StaticContext.DBContext.Addon.Where(a => a.NameLink == addon.NameLink).FirstOrDefault();
                if (savedAddon != null) addon.Skip = savedAddon.Skip;
                addon.Index = i;
                AddonCollection2BindingSource.Add(addon);
            }
            //AddonCollection2BindingSource.ResumeBinding();
            //AddonCollection2BindingSource.EndEdit();
            //dgvAddons.EndEdit();
            this.Refresh();

        }

        public bool ShowError(string errorText) {
            MessageBox.Show(errorText);
            return true;
        }

        private int CheckedAddonCount(List<Addon> addons) {
            int result = 0;
            foreach (Addon addon in addons) {
                if (addon.Checked) result++;
            }
            return result;
        }

        private void AddonsUpdate() {
            if (CheckedAddonCount(Addons) < 1) {
                MessageBox.Show("Please select some addon to update.");
                UpdateButtonEnabled(true);
                return;
            }

            // wait 59 sec from last Download;
            TimeSpan needWait = DownloadSpan.RestrictionSpan - (DateTime.Now - Credo.LastDownload);
            if (needWait.Ticks > 0) {
                timer.Start();
                timer.Enabled = true;
                while (!ExitFlag) {
                    Application.DoEvents();
                }
            }
            else {
                CompareUpdate();
            }


        }

        private Addon GetByIndex(int i) {
            foreach (Addon addon in Addons) {
                if (addon.Index == i) return addon;
            }
            return null;
        }

        private void CompareUpdate() {
            int selectedItemsCount = CheckedAddonCount(Addons);

            #region Update
            SetProgress(0);

            FileInfo fileInfo = new FileInfo(Application.ExecutablePath);
            string exeFolder = fileInfo.Directory.ToString();
            string tempFolderName = fileInfo.Directory + "\\" + Guid.NewGuid().ToString();
            Directory.CreateDirectory(tempFolderName);

            int progressBar_downloadPart = 50;
            int progressBar_unzipPart = 20;
            int downloading_items_count = 0;

            for (int i = 0; i < dgvAddons.Rows.Count; i++) {
                DataGridViewRow row = dgvAddons.Rows[i];
                row.Cells[1].Style.ForeColor = Color.Black;
                Addon addon = GetByIndex(row.Index);

                if (!addon.Skip && addon.Checked) {
                    downloading_items_count++;
                    string message = "Downloading addon (" + downloading_items_count + " of " + selectedItemsCount + ") -> " + addon.Name;
                    SetStatus(message);
                    SetProgress((progressBar_downloadPart * downloading_items_count) / selectedItemsCount);

                    for (int a = 1; a < MaxTryCount; a++) {
                        try {
                            Credo.LastDownload = DateTime.Now;
                            MainRequest.Download(ref addon, tempFolderName, message);
                            Credo.LastDownload = DateTime.Now;
                            SyncronizeAddon(addon, false);
                            break;
                        }
                        catch (Exception ex) {
                            SetStatus("Downloading addon " + addon.Name + " failed, retrying (try nr. " + a + ").");
                            row.Cells[1].Style.ForeColor = Color.Red;
                            if (!Credo.TryContiniously) {
                                MessageBox.Show(ex.Message);
                            }
                        }
                    }

                }
            }

            SetStatus("Download done...");
            SetProgress(progressBar_downloadPart);

            // UnZiping
            string[] files_zip = Directory.GetFiles(tempFolderName, "*.zip");
            string[] files_rar = Directory.GetFiles(tempFolderName, "*.rar");

            int files_zip_Length = files_zip.Length;
            int files_rar_Length = files_rar.Length;
            int files_Length = files_rar_Length + files_zip_Length;

            string zipFolder = tempFolderName + "\\unzip";

            for (int i = 0; i < files_zip_Length; i++) {
                string file = files_zip[i];
                string fn = file.Replace(tempFolderName, "").Replace("\\", "");
                SetStatus("Extracting file " + fn);
                SetProgress(progressBar_downloadPart + ((progressBar_unzipPart * i) / (files_Length)));
                UnzipFile(file, zipFolder, fn);
            }

            for (int i = 0; i < files_rar_Length; i++) {
                string file = files_rar[i];
                string fn = file.Replace(tempFolderName, "").Replace("\\", "");
                SetStatus("Extracting file " + fn);
                SetProgress(progressBar_downloadPart + ((progressBar_unzipPart * i) / (files_Length)));
                UnrarFile(file, zipFolder, fn);
            }

            IStorage.SetCredentials(Credo);

            SetStatus("Extraction done...");
            SetProgress(progressBar_downloadPart + progressBar_unzipPart);

            string wowAddonsFolder = Constants.WoWFolder + "Interface\\AddOns";

            if (!Directory.Exists(wowAddonsFolder) && Directory.Exists(Constants.WoWFolder)) {
                Directory.CreateDirectory(wowAddonsFolder);
            }

            // Normalazing

            if (files_Length > 0 && Directory.Exists(zipFolder)) {
                foreach (string folder in Directory.GetDirectories(zipFolder)) {
                    SetStatus("Normalazing folder: " + folder.Replace(tempFolderName, "").Replace("\\unzip\\", ""));
                    GetRightFolders(folder, tempFolderName + "\\output");
                }
                if (Directory.Exists(tempFolderName + "\\output")) {
                    string[] addon_folders = Directory.GetDirectories(tempFolderName + "\\output");

                    SetProgress(progressBar_downloadPart + progressBar_unzipPart + 5);
                    if (Credo.MakeBackup) {
                        SetStatus("Backup...");

                        DateTime now = DateTime.Now;

                        string backupFolder = "Interface\\Addons_" + now.Year.ToString() + now.Month.ToString("00") + now.Date.ToString("00") + now.Hour.ToString("00") + now.Minute.ToString("00") + now.Second.ToString("00") + "";
                        backupFolder = Constants.WoWFolder != null ? Constants.WoWFolder + backupFolder : exeFolder + backupFolder;
                        // Backup
                        if (Constants.WoWFolder != null) {
                            foreach (string folder in Directory.GetDirectories(wowAddonsFolder)) {
                                foreach (string addon_folder in addon_folders) {
                                    if (folder.Replace(wowAddonsFolder + "\\", "").Equals(addon_folder.Replace(tempFolderName + "\\output\\", ""))) {
                                        CopyFolder(folder, backupFolder);
                                    }
                                }

                            }
                        }
                    }

                    SetStatus("Copying...");
                    SetProgress(progressBar_downloadPart + progressBar_unzipPart + 5);

                    // Copy
                    foreach (string folder in addon_folders) {
                        CopyFolder(folder, wowAddonsFolder);
                    }
                }
            }
            Directory.Delete(tempFolderName, true);
            SetStatus("Ready...");
            SetProgress(100);
            UpdateButtonEnabled(true);
            ColorAddons();
            #endregion
        }

        private void SyncronizeAddon(Addon addon, bool tocs) {
            Addon savedAddon = StaticContext.DBContext.Addon.Where(a => a.DownloadURL == addon.DownloadURL).FirstOrDefault();
            if (savedAddon == null) {
                addon.Id = Guid.NewGuid();
                StaticContext.DBContext.Addon.InsertOnSubmit(addon);
            }
            else {
                savedAddon.Name = addon.Name;
                savedAddon.UploadDate = addon.UploadDate;
                savedAddon.FileName = addon.FileName;
                savedAddon.Skip = addon.Skip;
                if (tocs) {
                    throw new NotImplementedException();
                }
            }
            StaticContext.DBContext.SubmitChanges();
        }

        private Addon GetByDownloadURL(List<Addon> addons, string downloadURL) {
            foreach (Addon addon in addons) {
                if (addon.DownloadURL == downloadURL) return addon;
            }
            return null;
        }


        private void SyncronizeAddons() {
            List<Addon> savedAddons = SavedAddons;
            foreach (Addon addon in Addons) {
                Addon savedAddon = GetByDownloadURL(savedAddons, addon.DownloadURL);
                if (savedAddon != null) {
                    addon.LocalDate = savedAddon.LocalDate;
                    addon.Skip = savedAddon.Skip;
                }
            }
        }

        private void UnzipFile(string path, string outputFolder, string file) {
            ArrayList files = new ArrayList();
            bool needFolder = false;
            Addon savedAddon = StaticContext.DBContext.Addon.Where(a => a.FileName == file).FirstOrDefault();
            string tocFolderNameTemp = null;
            
            try {
                ZipInputStream s = new ZipInputStream(File.OpenRead(path));
                ZipEntry theEntry;

                while ((theEntry = s.GetNextEntry()) != null) {

                    string entityFolder = Path.GetDirectoryName(theEntry.Name);
                    string directoryName = outputFolder + "\\" + entityFolder;
                    if (!needFolder && entityFolder == string.Empty) needFolder = true;
                    string fileName = Path.GetFileName(theEntry.Name);
                    files.Add(directoryName + "\\" + fileName);
                    
                    if (theEntry.Name.EndsWith(".toc")) {
                        string tocFolderName = theEntry.Name.Replace(fileName, "");
                        if (savedAddon.Toc == null || tocFolderNameTemp == null || tocFolderNameTemp.Length > tocFolderName.Length) {
                            tocFolderNameTemp = tocFolderName;
                            savedAddon.Toc = fileName;
                        }
                    }

                    // create directory
                    Directory.CreateDirectory(directoryName);

                    if (fileName != string.Empty) {
                        FileStream streamWriter = File.Create(outputFolder + "\\" + theEntry.Name);

                        int size = 2048;
                        byte[] data = new byte[2048];
                        while (true) {
                            size = s.Read(data, 0, data.Length);
                            if (size > 0) {
                                streamWriter.Write(data, 0, size);
                            }
                            else {
                                break;
                            }
                        }

                        streamWriter.Close();
                    }
                }
                s.Close();

                if (savedAddon.Toc == null) {
                    MessageBox.Show("There is no .toc file in addon " + savedAddon.Name);
                    return;
                }

                if (needFolder) {
                    string newFolder = savedAddon.Toc.Replace(".toc", "");
                    foreach (string fileName in files) {
                        FileInfo fi = new FileInfo(fileName);
                        if (fi.Exists) {
                            DirectoryInfo di = new DirectoryInfo(fi.DirectoryName + "\\" + newFolder);
                            if (!di.Exists) di.Create();
                            fi.CopyTo(fi.DirectoryName + "\\" + newFolder + "\\" + fi.Name);
                        }
                    }
                }
            }
            catch (Exception ex) {
                MessageBox.Show("Can not extract file " + file + "\ntry to downlaod and extract it manualy\nsystem message was: " + ex.Message);
            }
            StaticContext.DBContext.SubmitChanges();
        }

        private void UnrarFile(string path, string outputFolder, string file) {
            ArrayList files = new ArrayList();
            bool needFolder = false;
            Addon savedAddon = StaticContext.DBContext.Addon.Where(a => a.FileName == file).FirstOrDefault();

            Unrar unrar = null;
            try {
                // Get destination from user
                string directory = Path.GetDirectoryName(path); /// ???

                // Create new unrar class and attach event handlers for
                // progress, missing volumes, and password
                unrar = new Unrar();
                AttachHandlers(unrar);

                // Set destination path for all files
                unrar.DestinationPath = outputFolder;

                // Open archive for extraction
                unrar.Open(path, Unrar.OpenMode.Extract);

                // Extract each file found in hashtable
                while (unrar.ReadHeader()) {

                    string entityFolder = Path.GetDirectoryName(unrar.CurrentFile.FileName);
                    string directoryName = outputFolder + "\\" + entityFolder;
                    if (!needFolder && entityFolder == string.Empty && !unrar.CurrentFile.IsDirectory) needFolder = true;
                    string fileName = unrar.CurrentFile.IsDirectory ? "" : unrar.CurrentFile.FileName.Replace(entityFolder, "").Replace("\\", "");
                    if (!unrar.CurrentFile.IsDirectory) {
                        files.Add(directoryName + "\\" + fileName);
                    }

                    if (fileName.EndsWith(".toc") && !fileName.Contains("\\") && !fileName.Contains("//")) {
                        savedAddon.Toc = fileName;
                    }

                    unrar.Extract();
                }

                if (savedAddon.Toc == null) {
                    MessageBox.Show("There is no .toc file in addon " + savedAddon.Name);
                    return;
                }

                if (needFolder) {
                    string newFolder = savedAddon.Toc.Replace(".toc", "");
                    foreach (string fileName in files) {
                        FileInfo fi = new FileInfo(fileName);
                        if (fi.Exists) {
                            DirectoryInfo di = new DirectoryInfo(newFolder);
                            if (!di.Exists) di.Create();
                            fi.CopyTo(newFolder + "\\" + fi.Name);
                        }
                    }
                }

            }
            catch (Exception ex) {
                MessageBox.Show("Can not extract file " + file + "\ntry to downlaod and extract it manualy\n" + ex.Message + "\ncheck: unrar.dll must be in same folder as FavoritesAddonsRefresher.exe");
            }
            finally {
                if (unrar != null) {
                    unrar.Close();
                }
            }


        }

        private void AttachHandlers(Unrar unrar) {
            // unrar.ExtractionProgress += new ExtractionProgressHandler(unrar_ExtractionProgress);
            unrar.MissingVolume += new MissingVolumeHandler(unrar_MissingVolume);
            unrar.PasswordRequired += new PasswordRequiredHandler(unrar_PasswordRequired);
        }

        private void unrar_ExtractionProgress(object sender, ExtractionProgressEventArgs e) {
            // statusBar.Text = "Testing " + e.FileName;
            // progressBar.Value = (int)e.PercentComplete;
        }

        private void unrar_MissingVolume(object sender, MissingVolumeEventArgs e) {
            TextInputDialog dialog = new TextInputDialog();
            dialog.Value = e.VolumeName;
            dialog.Prompt = string.Format("Volume is missing.  Correct or cancel.");
            if (dialog.ShowDialog() == DialogResult.OK) {
                e.VolumeName = dialog.Value;
                e.ContinueOperation = true;
            }
            else
                e.ContinueOperation = false;
        }

        private void unrar_PasswordRequired(object sender, PasswordRequiredEventArgs e) {
            TextInputDialog dialog = new TextInputDialog();
            dialog.Prompt = string.Format("Password is required for extraction.");
            dialog.PasswordChar = '*';
            if (dialog.ShowDialog() == DialogResult.OK) {
                e.Password = dialog.Value;
                e.ContinueOperation = true;
            }
            else
                e.ContinueOperation = false;
        }

        private string ReplaceFoldersInName(string name) {
            string result = name.ToLower();
            string interf = "interface/";
            string addons = "addons/";
            if (result.StartsWith(interf)) {
                result = result.Substring(interf.Length);
            }

            if (result.StartsWith(addons)) {
                result = result.Substring(addons.Length);
            }

            return result;
        }

        private void GetRightFolders(string path, string outputPath) {
            string[] tocs = Directory.GetFiles(path, "*.toc");
            if (tocs.Length > 0) {
                foreach (string toc in tocs) {
                    FileInfo fn = new FileInfo(toc);
                    try {
                        Addon dbAddon = StaticContext.DBContext.Addon.Where(a => a.Toc.ToLower() == fn.Name.ToLower()).FirstOrDefault();
                        if (dbAddon != null) {
                            dbAddon.Path = fn.Directory.Name;
                            StaticContext.DBContext.SubmitChanges();
                        }
                    }
                    catch { }
                }
                CopyFolder(path, outputPath);
            }
            else {
                foreach (string folder in Directory.GetDirectories(path)) {
                    GetRightFolders(folder, outputPath);
                }
            }
        }

        private void CopyFolder(string path, string destination) {
            DirectoryInfo dir = new DirectoryInfo(path);
            try {
                DirectoryInfo targetDir = new DirectoryInfo(destination + "\\" + dir.Name);
                targetDir.Create();

                FileInfo[] files = dir.GetFiles();
                foreach (FileInfo file in files) {
                    file.CopyTo(destination + "\\" + dir.Name + "\\" + file.Name, true);
                }

                DirectoryInfo[] subDirs = dir.GetDirectories();
                foreach (DirectoryInfo subDir in subDirs) {
                    CopyFolder(subDir.FullName, targetDir.FullName);
                }
            }
            catch (Exception ex) {
                MessageBox.Show(ex.Message);
            }
        }

        private void ColorAddons() {
            if (SavedAddons.Count > 0) {
                int requireUpdateCount = 0;
                int requireDownloadCount = 0;
                foreach (DataGridViewRow row in dgvAddons.Rows) {
                    row.Cells[1].Style.ForeColor = Color.Green;
                }

                for (int i = 0; i < dgvAddons.Rows.Count; i++) {
                    DataGridViewRow row = dgvAddons.Rows[i];
                    Addon addon = GetByIndex(row.Index);
                    Addon savedAddon = GetByDownloadURL(SavedAddons, addon.DownloadURL);

                    if (savedAddon != null) {
                        savedAddon.NameLink = addon.NameLink;
                        if (savedAddon.Toc != null && savedAddon.Path != null) {
                            string fn = Constants.WoWFolder + "Interface\\Addons\\" + savedAddon.Path + "\\" + savedAddon.Toc;
                            FileInfo fi = new FileInfo(fn);
                            if (fi.Exists) {

                                DateTime result = fi.LastWriteTime > fi.LastAccessTime ? fi.LastWriteTime : fi.LastAccessTime;
                                if (result < fi.CreationTime) result = fi.CreationTime;
                                savedAddon.LocalDate = result;

                                try {
                                    addon.LocalDate = savedAddon.LocalDate;
                                }
                                catch { }


                                if (result == DateTime.MinValue) {
                                    SetRowColor(i, Color.Blue);
                                    addon.Checked = false;
                                }
                                else if (result < addon.UploadDate) {
                                    SetRowColor(i, Color.Red);
                                    requireUpdateCount++;
                                    addon.Checked = true;
                                }
                                else {
                                    SetRowColor(i, Color.Green);
                                    addon.Checked = false;
                                }
                            }
                            else {
                                savedAddon.Toc = null;
                                SetRowColor(i, Color.Red);
                            }
                        }
                        else {
                            addon.Checked = false;
                            SetRowColor(i, Color.BlueViolet);
                            if (!addon.Skip) {
                                requireDownloadCount++;
                            }
                        }
                    }
                    else {
                        SetRowColor(i, Color.BlueViolet);
                    }
                }
                EndEditAddons();
                SetStatus(requireUpdateCount + " addon(s) require update.  " + (requireDownloadCount > 0 ? (requireDownloadCount + " addon(s) require download.") : ""));
            }
            else {
                foreach (Addon addon in Addons) {
                    addon.Checked = true;
                    if (addon.Index.HasValue) {
                        SetRowColor(addon.Index.Value, Color.BlueViolet);
                    }
                }
            }
        }

        #region Custom

        #region dgv
        private void dgvAddons_Leave(object sender, EventArgs e) {
            EndEditAddons();
        }

        private void dgvAddons_MouseUp(object sender, MouseEventArgs e) {
            if (e.Button == MouseButtons.Right) {
                contextMenu.Show(dgvAddons, new Point(e.X, e.Y));
            }
        }

        private void dgvAddons_KeyUp(object sender, KeyEventArgs e) {
            EndEditAddons();
        }

        private void SetRowColor(int rowIndex, Color color) {
            DataGridViewRow row = dgvAddons.Rows[rowIndex];
            row.Cells[1].Style.ForeColor = color;
            row.Cells[2].Style.ForeColor = color;
            row.Cells[3].Style.ForeColor = color;
        }
        #endregion dgv

        public static int MakeInt(byte[] bb, int pos) {
            return bb[pos + 0] | (bb[pos + 1] << 8) | (bb[pos + 2] << 16) | (bb[pos + 3] << 24);
        }

        public static int MakeShort(byte[] bb, int pos) {
            return bb[pos + 0] | (bb[pos + 1] << 8);
        }

        private void timer_Tick(object sender, System.EventArgs e) {
            TimeSpan needWait = DownloadSpan.RestrictionSpan - (DateTime.Now - Credo.LastDownload);
            if (needWait.Ticks < 1) {
                SetStatus("restriction expired, downloading...");
                timer.Stop();
                ExitFlag = true;
                CompareUpdate();
            }
            else {
                SetStatus(string.Format("restriction for download, need wait {0} secs", decimal.Round((decimal)needWait.TotalSeconds, 0).ToString()));
            }
        }

        #endregion Custom

        #region Alternate Menu

        private void menuItem1_Click(object sender, System.EventArgs e) {
            EndEditAddons();
            foreach (Addon addon in AddonCollection2BindingSource.List) {
                addon.Checked = true;
            }
            EndEditAddons();
        }

        private void menuItem2_Click(object sender, System.EventArgs e) {
            EndEditAddons();
            foreach (Addon addon in AddonCollection2BindingSource.List) {
                addon.Checked = false;
            }
            EndEditAddons();
        }

        private void menuItem3_Click(object sender, System.EventArgs e) {
            EndEditAddons();
            foreach (Addon addon in AddonCollection2BindingSource.List) {
                addon.Checked = !addon.Checked;
            }
            EndEditAddons();
        }

        private void menuItem4_Click(object sender, System.EventArgs e) {
            EndEditAddons();
            foreach (Addon addon in AddonCollection2BindingSource.List) {
                addon.Checked = addon.LocalDate < addon.UploadDate;
            }
            EndEditAddons();
        }

        private void menuItem7_Click(object sender, EventArgs e) {
            Addon selectedAddon = GetSelectedAddon();
            string description = "No description";
            string changes = "No changes";
            if (selectedAddon.Description == null || selectedAddon.Description.Trim().Length == 0
                || selectedAddon.Changes == null || selectedAddon.Changes.Trim().Length == 0) {
                for (int i = 1; i < MaxTryCount; i++) {
                    try {
                        MainRequest.GetAddonHTML(ref selectedAddon);
                        break;
                    }
                    catch (Exception ex) {
                        if (!Credo.TryContiniously) {
                            MessageBox.Show(ex.Message);
                        }
                    }
                }
                description = selectedAddon.Description;
            }

            AddonInfo info = new AddonInfo(description);
            info.ShowDialog();
        }

        private void menuItem8_Click(object sender, EventArgs e) {
            Addon selectedAddon = GetSelectedAddon();
            for (int i = 1; i < MaxTryCount; i++) {
                try {
                    MainRequest.GetAddonHTML(ref selectedAddon);
                    break;
                }
                catch (Exception ex) {
                    if (!Credo.TryContiniously) {
                        MessageBox.Show(ex.Message);
                    }
                }
            }
            if (selectedAddon.DownloadURL != null) {
                System.Diagnostics.Process.Start(Constants.URL_WoWInterface_Download + selectedAddon.DownloadURL);
            }
            else {
                MessageBox.Show("There is no Download URL for this addon :(");
            }
        }

        private void menuItem9_Click(object sender, EventArgs e) {
            Addon selectedAddon = GetSelectedAddon();
            System.Diagnostics.Process.Start(selectedAddon.NameLink);
        }

        private Addon GetSelectedAddon() {
            foreach (DataGridViewRow row in dgvAddons.SelectedRows) {
                return Addons[row.Index];
            }
            return new Addon();
        }

        private void contextMenu_Popup(object sender, EventArgs e) {
            if (dgvAddons.RowCount == 0) contextMenu.Dispose();
            else {
                menuItem6.Visible = menuItem7.Visible = menuItem8.Visible = menuItem9.Visible = (dgvAddons.SelectedRows.Count > 0);
            }
        }
        #endregion

        #region Close

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
            BeforeClosing(true);
        }

        private void BeforeClosing(bool saveCredentials) {
            EndEditAddons();
            List<Addon> savedAddons = SavedAddons;
            foreach (Addon addon in Addons) {
                Addon savedAddon = GetByDownloadURL(savedAddons, addon.DownloadURL);
                if (savedAddon != null) {
                    savedAddon.Skip = addon.Skip;
                }
            }

            StaticContext.DBContext.SubmitChanges();

            if (saveCredentials) {
                IStorage.SetCredentials(Credo);
            }






        }

        #endregion Close

        private void tb_password_KeyUp(object sender, KeyEventArgs e) {
            if (e.KeyCode == Keys.Enter) {
                Login(Credo);
            }
        }

        private void btnOptions_Click(object sender, EventArgs e) {
            FormOptions options = new FormOptions(ref Credo);
            options.ShowDialog();
        }

    }
}
